#ifndef SCENE_GRAPH_NODE_H_
#define SCENE_GRAPH_NODE_H_

#include <irrlicht/irrList.h>
#include <irrlicht/matrix4.h>
#include <irrlicht/vector3d.h>

class SceneGraphNode
{
	/*
	** SceneGraphNode represents a node in the tree structure
	** of a scene. Children are dependent on parent nodes for
	** position and other transforms.
	*/
public:
	static const int TYPE = 0;
	
protected:
	// the scene graph structure
	// each node has a parent and children
	SceneGraphNode * parent;
	irr::core::list<SceneGraphNode*> children;

	// does the scene graph node own its children?
	bool ownsChildren;

	// the transform of the object relative to the parent
	//irr::core::matrix4 relative;
	irr::core::matrix4 scale;
	irr::core::matrix4 rotation;
	irr::core::matrix4 translation;

	// an absolute transform for the object
	irr::core::matrix4 absolute;

	// the type of node
	long type;

public:
	SceneGraphNode(SceneGraphNode * parent = NULL, 
		bool ownsChildren = false)
	{
		/*
		** construct a scene graph node from a parent.
		*/
		this->parent = parent;
		if (parent)
		{
			parent->addChild(this);
		}
		
		this->ownsChildren = ownsChildren;
		
		type = TYPE;
		
		// set the matrices to identities
		absolute.makeIdentity();
	}
	
	~SceneGraphNode()
	{
		/*
		** destroy a scene graph node.
		*/
		if (ownsChildren)
		{
			for (irr::core::list<SceneGraphNode*>::Iterator iter = children.begin();
				iter != children.end(); iter++)
			{
				delete *iter;
			}
		}
	}
	
	inline void addChild(SceneGraphNode * child)
	{
		/*
		** add a child to a scenegraph node.
		** modifies the parent as well.
		*/
		children.push_back(child);
		child->parent = this;
	}
	
	inline void removeChild(SceneGraphNode * child)
	{
		/*
		** remove a child from a scenegraph node.
		** modifies the parent.
		*/
		
		children.remove(child);
		child->parent = NULL;
	}
	
	inline void removeFromParent()
	{
		/*
		** remove the current scene graph node from
		** its parent.
		*/
		parent->removeChild(this);
	}
	
	inline SceneGraphNode * getParent()
	{
		// accessor for the parent
		return parent;
	}
	
	inline irr::core::list<SceneGraphNode*> getChildren()
	{
		// accessor for the children
		return children;
	}
	
	inline void setTranslation(irr::core::vector3df translation)
	{
		// setter for translation
		this->translation.setTranslation(translation);
	}
	
	inline void setRotation(irr::core::vector3df rotation)
	{
		// setter for rotation
		this->rotation.setRotationDegrees(rotation);
	}
	
	inline void setScale(irr::core::vector3df scale)
	{
		// setter for scale
		this->scale.setScale(scale);
	}
	
	inline irr::core::vector3df getTranslation()
	{
		// accessor for translation
		return translation.getTranslation();
	}
	
	inline irr::core::vector3df getRotation()
	{
		// accessor for rotation
		return rotation.getRotationDegrees();
	}
	
	inline irr::core::vector3df getScale()
	{
		// accessor for scale
		return scale.getScale();
	}
	
	inline irr::core::matrix4 getAbsoluteTransform()
	{
		// accessor for the absolute transform
		return absolute;
	}
	
	inline irr::core::vector3df getAbsTranslation()
	{
		// accessor for the absolute translation
		return absolute.getTranslation();
	}
	
	inline irr::core::vector3df getAbsRotation()
	{
		// accessor for the absolute rotation
		return absolute.getRotationDegrees();
	}
	
	inline irr::core::vector3df getAbsScale()
	{
		// accessor for the absolute scale
		return absolute.getScale();
	}
	
	inline void updateAbsTransform()
	{
		// update the Absolute transform based on the relative
		// transform.
		if (parent)
		{
			absolute = parent->absolute * translation * rotation * scale;
		}
	}
	
	inline void setType(long type)
	{
		// setter for the type of the node
		this->type = type;
	}
	
	inline long getType()
	{
		// accessor for the type of the node
		return type;
	}
	
	
};

#endif
